package com.haiwei.poi.word.bean;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.haiwei.poi.common.HaiweiArrayUtil;
import com.haiwei.poi.common.HaiweiListUtils;
import com.haiwei.poi.common.HaiweiStringUtil;
import com.haiwei.poi.common.exception.HaiweiGeneralException;
import com.haiwei.poi.common.json.HaiweiJsonUtil;
import com.haiwei.poi.common.nassert.HaiweiAssert;
import com.haiwei.poi.common.nassert.HaiweiAssertException;
import com.haiwei.poi.word.exception.HaiweiBeanException;
import com.haiwei.poi.word.manager.HaiweiPatternUtil;
import com.haiwei.poi.word.sign.HaiweiSignConstant;

import java.util.*;

import static com.haiwei.poi.common.json.HaiweiJsonUtil.isJson;

/**
 * 数据模型工具类.
 * 全是Map
 * 即：每个节点都是List<{key,value}>
 * 变量不允许重复，重复就会报错
 *
 * @date: 2022-06-24
 * @version: 1.0
 * @author: karry@haiwei.com
 */
public class HaiweiBeanUtil {
    private static ThreadLocal<Map<String,Object>> cache = new ThreadLocal<>();
    private static ThreadLocal<HaiweiBeanCallback> callBackCache = new ThreadLocal<>();
    
    /**
     * 打印
     */
    public static void print(){
        final Map<String, Object> cache = getCache();
        printMap(cache,"");
        System.out.println("");
    }
    
    private static void printMap(Map<String, Object> map,String space){
        space += "\t";
        if(map != null && map.size() > 0){
            final Set<String> keySet = map.keySet();
            if(HaiweiListUtils.isNotEmpty(keySet)){
                for(String key : keySet){
                    final Object o = map.get(key);
                    if(o == null){
                        System.out.println(space + "\t" + key + ":null");
                    }else if(o instanceof  Map){
                        System.out.println(space + "\t" + key + ":");
                        printMap((Map)o,space);
                    }else {
                        System.out.println(space + "\t" + key + ":"+o.toString());
                    }
                }
            }
        }
    }
    
    /**
     * 添加JSON
     * @param json
     * @param path
     */
    public static void setJson(String json,String path){
        HaiweiAssert.assertNotNull(json);
        HaiweiAssert.assertNotBlank(path);
        HaiweiAssert.assertTrue("json style invalid", isJson(json));
    
        final Object obj = JSON.parse(json);
        if(obj instanceof  JSONObject){
            saveJSONObject((JSONObject)obj, attachCache(path));
        }else if(obj instanceof  JSONArray){
            saveJSONArray((JSONArray)obj, attachCache(path));
        }else{
            throw new HaiweiGeneralException("invalid type " + obj.getClass().toString());
        }
    }
    
    /**
     * 直接设置Value
     * @param value
     * @param path
     */
    public static void setString(final String value,final String path){
        HaiweiAssert.assertNotNull(value);
        HaiweiAssert.assertNotBlank(path);
        int index = path.lastIndexOf(HaiweiSignConstant.SGIN_PATH_SEPARATOR1);
        if(index == -1) {
            // 不包含,说明是根目录
            getCache().put(path,value);
        }else{
            String acturePath = path.substring(0,index);
            String key = path.substring(index+1,path.length());
            attachCache(acturePath).put(key,value);
        }
    }
    
    /**
     * 添加数据
     */
    public static void setBean(Object obj,String path) {
        HaiweiAssert.assertNotNull(obj);
        setJson(HaiweiJsonUtil.toJson(obj),path);
    }
    
    /**
     * 添加Map到指定路径
     * @param map
     */
    public static void setBean(Map<String,Object> map,String path) {
        HaiweiAssert.assertNotNull(map);
        saveJSONObject(new JSONObject(map), attachCache(path) );
    }
    
    public static void setBean(Map<String,Object> map){
        setBean(map,null);
    }
    
    /**
     * 获取Cache对象
     * @return
     */
    private static Map<String,Object> getCache(){
        final Map<String, Object> stringObjectMap = cache.get();
        if(stringObjectMap != null){
            return stringObjectMap;
        }
        cache.set(new HashMap<>());
        return cache.get();
    }
    
    /**
     * 根据路径获取指定Map
     * @param path
     * @return
     */
    private static Map<String,Object> attachCache(String path){
        final Map<String, Object> cache = getCache();
        if(HaiweiStringUtil.isBlank(path)){
            return cache;
        }
        
        String[] paths = path.split(HaiweiSignConstant.SGIN_PATH_SEPARATOR);
        int len  = paths.length;
        int index = 0;
        String ptemp = null;
        Map<String, Object> this_ = cache;
        while (index  < len){
            ptemp = paths[index];
            if(HaiweiStringUtil.isBlank(ptemp)){
                throw new HaiweiBeanException("invalid path : " + path);
            }
            
            // 如果不包含就添加空Map
            if(!this_.containsKey(ptemp)){
                this_.put(ptemp,new HashMap<>());
            }
            // 指针下移
            this_ = (Map<String, Object>) this_.get(ptemp);
            index ++ ;
        }
        
        return this_;
    }
    
    private static void saveJSONObject(JSONObject jsonObject, Map<String, Object> catchMap) {
        Set<String> keyset = jsonObject.keySet();
        if(HaiweiListUtils.isNotEmpty(keyset)){
            for(String key: keyset){
                saveObject(catchMap, key, jsonObject.get(key));
            }
        }
    }
    
    private static void saveJSONArray(JSONArray jsonArray, Map<String, Object> catchMap) {
        if(jsonArray != null){
            for(int index = 0 ; index < jsonArray.size(); index++){
                saveObject(catchMap
                        ,index + ""
                        ,jsonArray.get(index));
            }
        }
    }
    
    private static void saveObject(Map<String, Object> catchMap, String key, Object obj) {
        if(obj != null){
            if(obj instanceof String){
                catchMap.put(key,obj.toString());
            }else if(obj instanceof JSONObject){
                catchMap.put(key,new HashMap<>());
                saveJSONObject((JSONObject)obj, (Map<String, Object>) catchMap.get(key));
            }else if(obj instanceof Map){
                catchMap.put(key,new HashMap<>());
                saveJSONObject(new JSONObject((Map)obj), (Map<String, Object>) catchMap.get(key));
            }else if(obj instanceof JSONArray){
                JSONArray array = (JSONArray)obj;
                if(array != null){
                    for(int index = 0 ; index < array.size(); index++){
                        if(!catchMap.containsKey(key)){
                            catchMap.put(key,new HashMap<>());
                        }
                        
                        saveObject((Map<String, Object>) catchMap.get(key)
                                ,index + ""
                                ,array.get(index));
                        
                       /* if(!catchMap.containsKey(key)){
                            catchMap.put(key,new HashMap<>());
                        }
                        Map<String, Object> cmap = (Map<String, Object>) catchMap.get(key);
                        if(!cmap.containsKey(index + "")){
                            cmap.put(index + "",new HashMap<>());
                        }
                        saveObject((Map<String, Object>) cmap.get(index + "")
                                ,index + ""
                                ,array.get(index));*/
                    }
                }
            }else if(obj instanceof Iterable){
                Iterator iterator1 = ((Iterable) obj).iterator();
                int index = 0;
                if(iterator1 != null){
                    while (iterator1.hasNext()){
                        if(!catchMap.containsKey(key)){
                            catchMap.put(key,new HashMap<>());
                        }
                        Map<String, Object> cmap = (Map<String, Object>) catchMap.get(key);
                        if(!cmap.containsKey(index + "")){
                            cmap.put(index + "",new HashMap<>());
                        }
                        
                        saveObject((Map<String, Object>) cmap.get(index + "")
                                ,index + ""
                                ,iterator1.next());
                        index ++;
                    }
                }
            }else {
                final String json = HaiweiJsonUtil.toJson(obj);
                if(isJson(json)){
                    catchMap.putAll(HaiweiJsonUtil.toMap(json));
                }else{
                    catchMap.put(key,obj.toString());
                }
            }
        }
    }
    
    /**
     * 设置回调
     * @param callback
     */
    public static void setCallBackCache(HaiweiBeanCallback callback){
        if(callback != null){
            callBackCache.set(callback);
        }
    }
    
    /**
     * 获取长度
     * @param path
     * @return
     */
    public static int getCollectionLen(String path){
        final Object value = getValue(path);
        if(value == null) {
            return 0;
        }
        
        if(value instanceof Map){
            return ((Map)value).size();
        }
        
        throw new HaiweiGeneralException("expected list but acture type is :" + value.getClass());
    }
    
    
    /**
     * customer.name
     * customer.paths.0.customer 这种场景稍后做
     * paths[1]: ^[a-z|A-Z]?[a-z|A-Z|0-9]+(\[[0-9]+\])?$
     * @param path
     */
    public static Object getValue(String path) {
        HaiweiAssert.assertNotBlank(path);
        path = HaiweiStringUtil.removeWhitespace(path);
        if (!HaiweiPatternUtil.checkPathChar(path)) {
            throw new HaiweiAssertException(String.format("path[%s] invalid", path));
        }
        
        String[] paths = path.split(HaiweiSignConstant.SGIN_PATH_SEPARATOR);
        if(HaiweiArrayUtil.isEmpty(paths)){
            throw new HaiweiAssertException(String.format("path[%s] invalid", path));
        }
        
        final Map<String, Object> cache = getCache();
        int len  = paths.length;
        int index = -1;
        String ptemp = null;
        Object objTemp = null;
        Map<String, Object> this_ = cache;
        while (index ++ < len){
            ptemp = paths[index];
            if(HaiweiStringUtil.isBlank(ptemp)){
                throw new HaiweiBeanException("invalid path : " + path);
            }
            
            // 如果不包含 就直接返回
            if(!this_.containsKey(ptemp)){
                return "";
            }
            
            // 指针下移
            objTemp = this_.get(ptemp);
            if(index + 1 == len){
                return objTemp;
            }else if(objTemp instanceof Map){
                this_ = (Map<String, Object>)objTemp;
            }else {
                return "";
            }
        }
        return "";
    }
    
    /**
     * 情况某路径数据
     * order
     * order.items
     * @param path
     */
    public static void clean(String path) {
        HaiweiAssert.assertNotBlank(path);
        int index = path.lastIndexOf(HaiweiSignConstant.SGIN_PATH_SEPARATOR1);
        if(index == -1) {
            // 不包含,说明是根目录
            getCache().remove(path);
        }else{
            String acturePath = path.substring(0,index);
            String key = path.substring(index+1,path.length());
            attachCache(acturePath).remove(key);
        }
    }
}
